#pragma once

#include <Signals.h>
#include <vector>
#include <boost/noncopyable.hpp>
#include <system/assert.h>
#include <Converter.h>
#include <CompilerFeatures.h>

namespace liba {
namespace properties {

class AbstractCommand
{
public:
	virtual bool Invoke(std::vector<std::string> args) = 0;
};

template<typename Signature>
class BaseCommand
	: public AbstractCommand
{
public:
	liba::signals::signal<Signature>& Invoked() { return this->invoked; }
protected:
	liba::signals::signal<Signature> invoked;
};

class Command0
	: public BaseCommand<void ()>
{
public:
	virtual bool Invoke(std::vector<std::string> args) LIBA_OVERRIDE
	{
		if (args.size() != 0)
		{
			LIBA_FAIL("Argument list length mismatch.");
			return false;
		}

		this->Invoke();
		return true;
	}

	void Invoke() { this->invoked(); }
};

template<typename T1>
class Command1
	: public BaseCommand<void (T1)>
{
public:
	virtual bool Invoke(std::vector<std::string> args) LIBA_OVERRIDE
	{
		if (args.size() != 1)
		{
			LIBA_FAIL("Argument list length mismatch");
			return false;
		}

		T1 arg1;
		if (!converter::convert(args[0], &arg1))
		{
			LIBA_FAIL("Failed to convert first argument");
			return false;
		}

		this->Invoke(arg1);
		return true;
	}

	void Invoke(T1 a1) { this->invoked(a1); }
private:
};

struct nothing {};

template<typename T1 = nothing>
class Command 
  : public Command1<T1>
  , private boost::noncopyable
{ 
};

template<>
class Command<nothing>
	: public Command0
	, private boost::noncopyable
{
};

} // namespace properties
} // namespace liba